package org.hcf.api.base;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import io.netty.util.internal.shaded.org.jctools.queues.ConcurrentCircularArrayQueue;
import lombok.extern.slf4j.Slf4j;
import org.hcf.api.config.PluginConf;
import org.hcf.api.config.ResConf;
import org.hcf.api.config.TencentConf;
import org.hcf.common.UserSigInfo;
import org.hcf.common.util.TLSSigAPIv2;
import org.hcf.data.RedisUtils;
import org.hcf.data.cache.CacheConfig;
import org.hcf.data.cache.Caches;
import org.hcf.data.entity.ChatGroupInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.tio.utils.cache.CacheUtils;
import org.tio.utils.cache.FirsthandCreater;
import org.tio.utils.cache.ICache;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.stream.Collectors;

@Slf4j
@Order(1)
@Component
public class Helper {
    @Autowired
    ResConf res;
    @Autowired
    TencentConf conf;
    @Autowired
    PluginConf plugin;
    @Value("${server.port}")
    int port;
    public static ResConf RES;
    public static TencentConf CONF;
    public static PluginConf PLUGIN;
    public static TLSSigAPIv2 API;
    //    public static File MatrixDir;
//    public static boolean hasMatrixPath;
    public static String LocalURL;

    public static Map<Long, Collection<String>> pluginPushMsg = new ConcurrentHashMap<>();

    static void addPluginPushMsg(String content) {
        long now = System.currentTimeMillis();
        Collection<String> datas = pluginPushMsg.get(now);
        if (datas == null) {
            datas = new LinkedList<>();
            pluginPushMsg.put(now, datas);
        }
        datas.add(content);
    }

    @PostConstruct
    void init() {
        RES = res;
        CONF = conf;
        PLUGIN = plugin;
        API = new TLSSigAPIv2(CONF.getAppId(), CONF.getAppSecret());
        if (!FileUtil.exist(Helper.RES.getDir() + "/matrix/")) FileUtil.mkdir(Helper.RES.getDir() + "/matrix/");
//        MatrixDir = new File(Helper.RES.getDir() + "/matrix/");
//        hasMatrixPath = MatrixDir.exists();
//        isHasMatrixPath();
        LocalURL = Helper.RES.getUrl().substring(0, Helper.RES.getUrl().lastIndexOf(":")) + ":" + port;
        log.info("本地Api地址:" + LocalURL);
        log.info("RES_CONFIG" + JSONObject.toJSONString(res));
        log.info("TENCENT_CONFIG:" + JSONObject.toJSONString(conf));
        log.info("PLUGIN_CONFIG:" + JSONObject.toJSONString(plugin));
    }

//    boolean isHasMatrixPath() {
//        if (!hasMatrixPath) {
//            MatrixDir.mkdirs();
//            hasMatrixPath = MatrixDir.exists();
//        }
//        return hasMatrixPath;
//    }

    public static String getParam() {
        return "sdkappid=" + CONF.getAppId() + "&identifier=" + CONF.getAdminUserName() + "&usersig=" + Helper.getAdminSig() + "&random=" + RandomUtil.randomInt(0, Integer.MAX_VALUE) + "&contenttype=json";
    }

    public static String getAPI(String restapi) {
        return CONF.getUrl() + restapi + "?" + getParam();
    }

    public static String getAdminSig() {
        long now = System.currentTimeMillis();
        UserSigInfo info = RedisUtils.getUserSig(0);
        if (info == null || info.getTimeout() <= System.currentTimeMillis()) {
            String userSig = API.genUserSig(CONF.getAdminUserName(), CacheConfig.USER_SIG.getTimeToLiveSeconds());
            info = new UserSigInfo();
            info.setUserId(0);
            info.setTimeout(now + CacheConfig.USER_SIG.getTimeToLiveSeconds());
            info.setUserSig(userSig);
            RedisUtils.put(info);
        }
        return info.getUserSig();
    }

    public static String getUserSig(long userId) {
        if (userId <= 0) return null;
        long now = System.currentTimeMillis();
        UserSigInfo info = RedisUtils.getUserSig(userId);
        if (info == null || info.getTimeout() <= System.currentTimeMillis()) {
            String userSig = API.genUserSig(String.valueOf(userId), CacheConfig.USER_SIG.getTimeToLiveSeconds());
            info = new UserSigInfo();
            info.setUserId(userId);
            info.setTimeout(now + CacheConfig.USER_SIG.getTimeToLiveSeconds());
            info.setUserSig(userSig);
            RedisUtils.put(info);
        }
        return info.getUserSig();
    }

    public static void sendToPlugin(long from, long uid, String to, String content, long msgId) {
        String qrCodeId = Caches.getCache(CacheConfig.PLUGIN_USER_QR).get(String.valueOf(uid), String.class);
        long wcid = uid;
        if (qrCodeId == null) {
            wcid = from;
            qrCodeId = Caches.getCache(CacheConfig.PLUGIN_USER_QR).get(String.valueOf(from), String.class);
            if (qrCodeId == null) return;
        }
        JSONObject json = new JSONObject();
        JSONObject data = new JSONObject();
        data.put("content", content);
        data.put("fromUser", from);
        data.put("newMsgId", msgId);
        data.put("timestamp", System.currentTimeMillis());
        data.put("toUser", to);
        json.put("data", data);
        json.put("messageType", 5);
        json.put("wcId", wcid);
        try {
            if (PLUGIN.getIsOpen()) {

                addPluginPushMsg(json.toJSONString());
//                String res = HttpUtil.post(PLUGIN.getUrl(), json.toJSONString());
//                log.info("[" + from + "]向plugin用户[" + wcid + "]服务端推送消息:" + json + "; 结果:" + res);
            } else
                log.info("PLUGIN推送接口[" + PLUGIN.getIsOpen() + "],不向plugin用户[" + wcid + "]服务端推送消息:" + json);
        } catch (Exception ex) {
            log.error("[" + from + "]向plugin用户[" + wcid + "]服务端发送HTTP请求异常!!!", ex);
        }
    }

    public static void sendOfflineToPlugin(long userId) {
        JSONObject json = new JSONObject();
        try {
            JSONObject data = new JSONObject();
            data.put("content", "您已退出微信/session过期");
            json.put("data", data);
            json.put("messageType", 30000);
            json.put("wcId", userId);
            if (PLUGIN.getIsOpen()) {
                String res = HttpUtil.post(PLUGIN.getUrl(), json.toJSONString());
                log.info("向plugin用户[" + userId + "]发送离线消息:" + json + "; 结果:" + res);
            } else
                log.info("PLUGIN推送接口[" + PLUGIN.getIsOpen() + "],不向plugin用户[" + userId + "]推送离线消息:" + json);
        } catch (Throwable ex) {
            log.error("向plugin服务端用户[" + userId + "]发送离线消息[" + json + "]异常!!!", ex);
        }
    }

//    public static Set<Long> createPluginUserGroup(Long userId) {
//        ICache cache = Caches.getCache(CacheConfig.PLUGIN_USER_GROUP);
//        return CacheUtils.get(cache, userId.toString(), new FirsthandCreater<HashSet<Long>>() {
//            @Override
//            public HashSet<Long> create() {
//                Set<ChatGroupInfo> members = RedisUtils.getGroupMemberFromUser(userId);
//                if (members != null) {
//                    return new HashSet<>(members.stream().filter(v -> v.isKeepGroup()).map(v -> v.getGroupId()).collect(Collectors.toSet()));
//                }
//                return null;
//            }
//        });
//    }

    static int staIndex = 0;

    public static int getStaIndex(String key) {
        if (staIndex <= 0) {
            staIndex = key.lastIndexOf(":") + 1;
        }
        return staIndex;
    }

    public static Set<Long> getPluginUserIds() {
        Iterable<String> ks = Caches.getCache(CacheConfig.PLUGIN_USER_QR).keys();
        Set<Long> uids = new HashSet<>();
        for (String k : ks) {
            String key = k.substring(getStaIndex(k), k.length());
            if (StrUtil.isNotBlank(key) && NumberUtil.isNumber(key)) uids.add(Long.parseLong(key));
        }
        return uids;
    }


    public static JSONObject toSuccess() {
        JSONObject json = new JSONObject();
        json.put("ActionStatus", "OK");
        json.put("ErrorInfo", "OK");
        json.put("ErrorCode", 0);
        return json;
    }
}
